namespace GYLite{
    export class Matrix4x4{
        private static _tempMatrix4x4:Matrix4x4 = new Matrix4x4();
        private static _tempVector0:Vector3 = new Vector3();
        private static _tempVector1:Vector3 = new Vector3();
        private static _tempVector2:Vector3 = new Vector3();
        private static _tempQuaternion:Quaternion;
        private static DEFAULT:Matrix4x4 = new Matrix4x4();
        private static ZERO:Matrix4x4 = new Matrix4x4();
        
        public static get tempQuaternion():Quaternion
        {
            return this._tempQuaternion = this._tempQuaternion || new Quaternion();
        }


        public elements:Float32Array;
        constructor(m11:number=1, m12:number=0, m13:number=0, m14:number=0, m21:number=0, m22:number=1, m23:number=0, m24:number=0, m31:number=0, m32:number=0, m33:number=0, m34:number=1, m41:number=0, m42:number=0, m43:number=0, m44:number=1) {
            /**矩阵元素数组*/
            //this.elements=null;            
            var e:Float32Array = this.elements = new Float32Array(16);
            e[0] = m11;
            e[1] = m12;
            e[2] = m13;
            e[3] = m14;
            e[4] = m21;
            e[5] = m22;
            e[6] = m23;
            e[7] = m24;
            e[8] = m31;
            e[9] = m32;
            e[10] = m33;
            e[11] = m34;
            e[12] = m41;
            e[13] = m42;
            e[14] = m43;
            e[15] = m44;
        }
        public getElementByRowColumn(row:number, column:number):number {
            if (row < 0 || row > 3)
                throw new Error("row:Rows and columns for matrices run from 0 to 3, inclusive.");
            if (column < 0 || column > 3)
                throw new Error("column:Rows and columns for matrices run from 0 to 3, inclusive.");
            return this.elements[(row * 4) + column];
        }
    
        public setElementByRowColumn(row:number, column:number, value:number):void {
            if (row < 0 || row > 3)
                throw new Error("row:Rows and columns for matrices run from 0 to 3, inclusive.");
            if (column < 0 || column > 3)
                throw new Error("column:Rows and columns for matrices run from 0 to 3, inclusive.");
            this.elements[(row * 4) + column] = value;
        }
    
        /**
         *判断两个4x4矩阵的值是否相等。
        *@param other 4x4矩阵
        */
        public equalsOtherMatrix(other:Matrix4x4):boolean {
            var e:Float32Array = this.elements;
            var oe:Float32Array = other.elements;
            return (MathUtils3D.nearEqual(e[0], oe[0]) && MathUtils3D.nearEqual(e[1], oe[1]) && MathUtils3D.nearEqual(e[2], oe[2]) && MathUtils3D.nearEqual(e[3], oe[3]) && MathUtils3D.nearEqual(e[4], oe[4]) && MathUtils3D.nearEqual(e[5], oe[5]) && MathUtils3D.nearEqual(e[6], oe[6]) && MathUtils3D.nearEqual(e[7], oe[7]) && MathUtils3D.nearEqual(e[8], oe[8]) && MathUtils3D.nearEqual(e[9], oe[9]) && MathUtils3D.nearEqual(e[10], oe[10]) && MathUtils3D.nearEqual(e[11], oe[11]) && MathUtils3D.nearEqual(e[12], oe[12]) && MathUtils3D.nearEqual(e[13], oe[13]) && MathUtils3D.nearEqual(e[14], oe[14]) && MathUtils3D.nearEqual(e[15], oe[15]));
        }
    
        /**
         *分解矩阵为平移向量、旋转四元数、缩放向量。
        *@param translation 平移向量。
        *@param rotation 旋转四元数。
        *@param scale 缩放向量。
        *@return 是否分解成功。
        */
        public decomposeTransRotScale(translation:Vector3, rotation:Quaternion, scale:Vector3):boolean {
            var rotationMatrix:Matrix4x4 = Matrix4x4._tempMatrix4x4;
            if (this.decomposeTransRotMatScale(translation, rotationMatrix, scale)) {
                Quaternion.createFromMatrix4x4(rotationMatrix, rotation);
                return true;
            } else {
                rotation.identity();
                return false;
            }
        }
    
        /**
         *分解矩阵为平移向量、旋转矩阵、缩放向量。
        *@param translation 平移向量。
        *@param rotationMatrix 旋转矩阵。
        *@param scale 缩放向量。
        *@return 是否分解成功。
        */
        public decomposeTransRotMatScale(translation:Vector3, rotationMatrix:Matrix4x4, scale:Vector3):boolean {
            var e:Float32Array = this.elements;
            var te:Float32Array = translation.elements;
            var re:Float32Array = rotationMatrix.elements;
            var se:Float32Array = scale.elements;
            te[0] = e[12];
            te[1] = e[13];
            te[2] = e[14];
            var m11 = e[0], m12 = e[1], m13 = e[2];
            var m21 = e[4], m22 = e[5], m23 = e[6];
            var m31 = e[8], m32 = e[9], m33 = e[10];
            var sX = se[0] = Math.sqrt((m11 * m11) + (m12 * m12) + (m13 * m13));
            var sY = se[1] = Math.sqrt((m21 * m21) + (m22 * m22) + (m23 * m23));
            var sZ = se[2] = Math.sqrt((m31 * m31) + (m32 * m32) + (m33 * m33));
            if (MathUtils3D.isZero(sX) || MathUtils3D.isZero(sY) || MathUtils3D.isZero(sZ)) {
                re[1] = re[2] = re[3] = re[4] = re[6] = re[7] = re[8] = re[9] = re[11] = re[12] = re[13] = re[14] = 0;
                re[0] = re[5] = re[10] = re[15] = 1;
                return false;
            }
            ;
            var at:Vector3 = Matrix4x4._tempVector0;
            var atE:Float32Array = at.elements;
            atE[0] = m31 / sZ;
            atE[1] = m32 / sZ;
            atE[2] = m33 / sZ;
            var tempRight:Vector3 = Matrix4x4._tempVector1;
            var tempRightE:Float32Array = tempRight.elements;
            tempRightE[0] = m11 / sX;
            tempRightE[1] = m12 / sX;
            tempRightE[2] = m13 / sX;
            var up:Vector3 = Matrix4x4._tempVector2;
            Vector3.cross(at, tempRight, up);
            var right:Vector3 = Matrix4x4._tempVector1;
            Vector3.cross(up, at, right);
            re[3] = re[7] = re[11] = re[12] = re[13] = re[14] = 0;
            re[15] = 1;
            re[0] = right.x;
            re[1] = right.y;
            re[2] = right.z;
            re[4] = up.x;
            re[5] = up.y;
            re[6] = up.z;
            re[8] = at.x;
            re[9] = at.y;
            re[10] = at.z;
            ((re[0] * m11 + re[1] * m12 + re[2] * m13) < 0.0) && (se[0] = -sX);
            ((re[4] * m21 + re[5] * m22 + re[6] * m23) < 0.0) && (se[1] = -sY);
            ((re[8] * m31 + re[9] * m32 + re[10] * m33) < 0.0) && (se[2] = -sZ);
            return true;
        }
    
        /**
         *分解旋转矩阵的旋转为YawPitchRoll欧拉角。
        *@param out float yaw
        *@param out float pitch
        *@param out float roll
        *@return
        */
        public decomposeYawPitchRoll(yawPitchRoll:Vector3):void {
            var yawPitchRollE:Float32Array = yawPitchRoll.elements;
            var pitch:number = Math.asin(-this.elements[9]);
            yawPitchRollE[1] = pitch;
            var test:number = Math.cos(pitch);
            if (test > MathUtils3D.zeroTolerance) {
                yawPitchRollE[2] = Math.atan2(this.elements[1], this.elements[5]);
                yawPitchRollE[0] = Math.atan2(this.elements[8], this.elements[10]);
            } else {
                yawPitchRollE[2] = Math.atan2(-this.elements[4], this.elements[0]);
                yawPitchRollE[0] = 0.0;
            }
        }
    
        /**归一化矩阵 */
        public normalize():void {
            var v:Float32Array = this.elements;
            var c:number = v[0], d:number = v[1], e:number = v[2], g:number = Math.sqrt(c * c + d * d + e * e);
            if (g) {
                if (g == 1)
                    return;
            } else {
                v[0] = 0;
                v[1] = 0;
                v[2] = 0;
                return;
            }
            g = 1 / g;
            v[0] = c * g;
            v[1] = d * g;
            v[2] = e * g;
        }
    
        /**计算矩阵的转置矩阵*/
        public transpose():Matrix4x4 {
            var e:Float32Array, t:number;
            e = this.elements;
            t = e[1];
            e[1] = e[4];
            e[4] = t;
            t = e[2];
            e[2] = e[8];
            e[8] = t;
            t = e[3];
            e[3] = e[12];
            e[12] = t;
            t = e[6];
            e[6] = e[9];
            e[9] = t;
            t = e[7];
            e[7] = e[13];
            e[13] = t;
            t = e[11];
            e[11] = e[14];
            e[14] = t;
            return this;
        }
    
        /**
         *计算一个矩阵的逆矩阵
        *@param out 输出矩阵
        */
        public invert(out:Matrix4x4):void {
            var ae:Float32Array = this.elements;
            var oe:Float32Array = out.elements;
            var a00:number = ae[0], a01:number = ae[1], a02:number = ae[2], a03:number = ae[3], a10:number = ae[4], a11:number = ae[5], a12:number = ae[6], a13:number = ae[7],
                a20:number = ae[8], a21:number = ae[9], a22:number = ae[10], a23:number = ae[11], a30:number = ae[12], a31:number = ae[13], a32:number = ae[14],
                a33:number = ae[15],
                b00:number = a00 * a11 - a01 * a10, b01:number = a00 * a12 - a02 * a10, b02:number = a00 * a13 - a03 * a10,
                b03:number = a01 * a12 - a02 * a11, b04:number = a01 * a13 - a03 * a11, b05:number = a02 * a13 - a03 * a12,
                b06:number = a20 * a31 - a21 * a30, b07:number = a20 * a32 - a22 * a30, b08:number = a20 * a33 - a23 * a30,
                b09:number = a21 * a32 - a22 * a31, b10:number = a21 * a33 - a23 * a31, b11:number = a22 * a33 - a23 * a32,
                det:number = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
            if (Math.abs(det) === 0.0) {
                return;
            }
            det = 1.0 / det;
            oe[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
            oe[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
            oe[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
            oe[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
            oe[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
            oe[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
            oe[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
            oe[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
            oe[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
            oe[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
            oe[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
            oe[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
            oe[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
            oe[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
            oe[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
            oe[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
        }
    
        /**设置矩阵为单位矩阵*/
        public identity():void {
            var e:Float32Array = this.elements;
            e[1] = e[2] = e[3] = e[4] = e[6] = e[7] = e[8] = e[9] = e[11] = e[12] = e[13] = e[14] = 0;
            e[0] = e[5] = e[10] = e[15] = 1;
        }
    
        /**
         *克隆。
        *@param destObject 克隆源。
        */
        public cloneTo(destObject:Matrix4x4):void {
            var i:number, s:Float32Array, d:Float32Array;
            s = this.elements;
            d = destObject.elements;
            if (s === d) {
                return;
            }
            for (i = 0; i < 16; ++i) {
                d[i] = s[i];
            }
        }
    
        /**
         *克隆。
        *@return 克隆副本。
        */
        public clone():Matrix4x4 {
            let s= this;
            let cls:any = s.constructor;
            var dest = new cls();
            this.cloneTo(dest);
            return dest;
        }
    
        /**
         *获取平移向量。
        *@param out 平移向量。
        */
        public getTranslationVector(out:Vector3):void {
            var me:Float32Array = this.elements;
            var te:Float32Array = out.elements;
            te[0] = me[12];
            te[1] = me[13];
            te[2] = me[14];
        }
    
        /**
         *设置平移向量。
        *@param translate 平移向量。
        */
        public setTranslationVector(translate:Vector3):void {
            var me:Float32Array = this.elements;
            var ve:Float32Array = translate.elements;
            me[12] = ve[0];
            me[13] = ve[1];
            me[14] = ve[2];
        }
    
        /**
         *获取前向量。
        *@param out 前向量。
        */
        public getForward(out:Vector3):void {
            var me:Float32Array = this.elements;
            var te:Float32Array = out.elements;
            te[0] = -me[8];
            te[1] = -me[9];
            te[2] = -me[10];
        }
    
        /**
         *设置前向量。
        *@param forward 前向量。
        */
        public setForward(forward:Vector3):void {
            var me:Float32Array = this.elements;
            var ve:Float32Array = forward.elements;
            me[8] = -ve[0];
            me[9] = -ve[1];
            me[10] = -ve[2];
        }
    
        public static createRotationX(rad:number, out:Matrix4x4):void {
            var oe:Float32Array = out.elements;
            var s:number = Math.sin(rad), c:number = Math.cos(rad);
            oe[1] = oe[2] = oe[3] = oe[4] = oe[7] = oe[8] = oe[11] = oe[12] = oe[13] = oe[14] = 0;
            oe[0] = oe[15] = 1;
            oe[5] = oe[10] = c;
            oe[6] = s;
            oe[9] = -s;
        }
    
        public static createRotationY(rad:number, out:Matrix4x4):void {
            var oe:Float32Array = out.elements;
            var s:number = Math.sin(rad), c:number = Math.cos(rad);
            oe[1] = oe[3] = oe[4] = oe[6] = oe[7] = oe[9] = oe[11] = oe[12] = oe[13] = oe[14] = 0;
            oe[5] = oe[15] = 1;
            oe[0] = oe[10] = c;
            oe[2] = -s;
            oe[8] = s;
        }
    
        public static createRotationZ(rad:number, out:Matrix4x4):void {
            var oe:Float32Array = out.elements;
            var s:number = Math.sin(rad), c:number = Math.cos(rad);
            oe[2] = oe[3] = oe[6] = oe[7] = oe[8] = oe[9] = oe[11] = oe[12] = oe[13] = oe[14] = 0;
            oe[10] = oe[15] = 1;
            oe[0] = oe[5] = c;
            oe[1] = s;
            oe[4] = -s;
        }
    
        public static createRotationYawPitchRoll(yaw:number, pitch:number, roll:number, result:Matrix4x4) {
            Quaternion.createFromYawPitchRoll(yaw, pitch, roll, Matrix4x4.tempQuaternion);
            Matrix4x4.createRotationQuaternion(Matrix4x4.tempQuaternion, result);
        }
    
        public static createRotationAxis(axis:Vector3, angle:number, result:Matrix4x4):void {
            var axisE:Float32Array = axis.elements;
            var x:number = axisE[0];
            var y:number = axisE[1];
            var z:number = axisE[2];
            var cos:number = Math.cos(angle);
            var sin:number = Math.sin(angle);
            var xx:number = x * x;
            var yy:number = y * y;
            var zz:number = z * z;
            var xy:number = x * y;
            var xz:number = x * z;
            var yz:number = y * z;
            var resultE:Float32Array = result.elements;
            resultE[3] = resultE[7] = resultE[11] = resultE[12] = resultE[13] = resultE[14] = 0;
            resultE[15] = 1.0;
            resultE[0] = xx + (cos * (1.0 - xx));
            resultE[1] = (xy - (cos * xy)) + (sin * z);
            resultE[2] = (xz - (cos * xz)) - (sin * y);
            resultE[4] = (xy - (cos * xy)) - (sin * z);
            resultE[5] = yy + (cos * (1.0 - yy));
            resultE[6] = (yz - (cos * yz)) + (sin * x);
            resultE[8] = (xz - (cos * xz)) + (sin * y);
            resultE[9] = (yz - (cos * yz)) - (sin * x);
            resultE[10] = zz + (cos * (1.0 - zz));
        }
    
        public static createRotationQuaternion(rotation:Quaternion, result:Matrix4x4):void {
            var rotationE:Float32Array = rotation.elements;
            var resultE:Float32Array = result.elements;
            var rotationX:number = rotationE[0];
            var rotationY:number = rotationE[1];
            var rotationZ:number = rotationE[2];
            var rotationW:number = rotationE[3];
            var xx:number = rotationX * rotationX;
            var yy:number = rotationY * rotationY;
            var zz:number = rotationZ * rotationZ;
            var xy:number = rotationX * rotationY;
            var zw:number = rotationZ * rotationW;
            var zx:number = rotationZ * rotationX;
            var yw:number = rotationY * rotationW;
            var yz:number = rotationY * rotationZ;
            var xw:number = rotationX * rotationW;
            resultE[3] = resultE[7] = resultE[11] = resultE[12] = resultE[13] = resultE[14] = 0;
            resultE[15] = 1.0;
            resultE[0] = 1.0 - (2.0 * (yy + zz));
            resultE[1] = 2.0 * (xy + zw);
            resultE[2] = 2.0 * (zx - yw);
            resultE[4] = 2.0 * (xy - zw);
            resultE[5] = 1.0 - (2.0 * (zz + xx));
            resultE[6] = 2.0 * (yz + xw);
            resultE[8] = 2.0 * (zx + yw);
            resultE[9] = 2.0 * (yz - xw);
            resultE[10] = 1.0 - (2.0 * (yy + xx));
        }
    
        public static createTranslate(trans:Vector3, out:Matrix4x4):void {
            var te:Float32Array = trans.elements;
            var oe:Float32Array = out.elements;
            oe[4] = oe[8] = oe[1] = oe[9] = oe[2] = oe[6] = oe[3] = oe[7] = oe[11] = 0;
            oe[0] = oe[5] = oe[10] = oe[15] = 1;
            oe[12] = te[0];
            oe[13] = te[1];
            oe[14] = te[2];
        }
    
        public static createScaling(scale:Vector3, out:Matrix4x4):void {
            var se:Float32Array = scale.elements;
            var oe:Float32Array = out.elements;
            oe[0] = se[0];
            oe[5] = se[1];
            oe[10] = se[2];
            oe[1] = oe[4] = oe[8] = oe[12] = oe[9] = oe[13] = oe[2] = oe[6] = oe[14] = oe[3] = oe[7] = oe[11] = 0;
            oe[15] = 1;
        }
    
        public static multiply(left:Matrix4x4, right:Matrix4x4, out:Matrix4x4):void {
            var i:number, e:Float32Array, a:Float32Array, b:Float32Array, ai0:number, ai1:number, ai2:number, ai3:number;
            e = out.elements;
            a = left.elements;
            b = right.elements;
            if (e === b) {
                // b = new Float32Array(16);
                // for (i = 0; i < 16; ++i) {
                //     b[i] = e[i];
                // }
                b = b.slice();
            }
            for (i = 0; i < 4; i++) {
                ai0 = a[i];
                ai1 = a[i + 4];
                ai2 = a[i + 8];
                ai3 = a[i + 12];
                e[i] = ai0 * b[0] + ai1 * b[1] + ai2 * b[2] + ai3 * b[3];
                e[i + 4] = ai0 * b[4] + ai1 * b[5] + ai2 * b[6] + ai3 * b[7];
                e[i + 8] = ai0 * b[8] + ai1 * b[9] + ai2 * b[10] + ai3 * b[11];
                e[i + 12] = ai0 * b[12] + ai1 * b[13] + ai2 * b[14] + ai3 * b[15];
            }
        }
    
        public static createFromQuaternion(rotation:Quaternion, out:Matrix4x4):void {
            var e:Float32Array = out.elements;
            var q:Float32Array = rotation.elements;
            var x:number = q[0], y:number = q[1], z:number = q[2], w:number = q[3];
            var x2 = x + x;
            var y2 = y + y;
            var z2 = z + z;
            var xx = x * x2;
            var yx = y * x2;
            var yy = y * y2;
            var zx = z * x2;
            var zy = z * y2;
            var zz = z * z2;
            var wx = w * x2;
            var wy = w * y2;
            var wz = w * z2;
            e[0] = 1 - yy - zz;
            e[1] = yx + wz;
            e[2] = zx - wy;
            e[3] = 0;
            e[4] = yx - wz;
            e[5] = 1 - xx - zz;
            e[6] = zy + wx;
            e[7] = 0;
            e[8] = zx + wy;
            e[9] = zy - wx;
            e[10] = 1 - xx - yy;
            e[11] = 0;
            e[12] = 0;
            e[13] = 0;
            e[14] = 0;
            e[15] = 1;
        }
    
        public static createAffineTransformation(trans:Vector3, rot:Quaternion, scale:Vector3, out:Matrix4x4):void {
            var te:Float32Array = trans.elements;
            var re:Float32Array = rot.elements;
            var se:Float32Array = scale.elements;
            var oe:Float32Array = out.elements;
            var x = re[0], y = re[1], z = re[2], w = re[3], x2 = x + x, y2 = y + y, z2 = z + z;
            var xx = x * x2, xy = x * y2, xz = x * z2, yy = y * y2, yz = y * z2, zz = z * z2;
            var wx = w * x2, wy = w * y2, wz = w * z2, sx = se[0], sy = se[1], sz = se[2];
            oe[0] = (1 - (yy + zz)) * sx;
            oe[1] = (xy + wz) * sx;
            oe[2] = (xz - wy) * sx;
            oe[3] = 0;
            oe[4] = (xy - wz) * sy;
            oe[5] = (1 - (xx + zz)) * sy;
            oe[6] = (yz + wx) * sy;
            oe[7] = 0;
            oe[8] = (xz + wy) * sz;
            oe[9] = (yz - wx) * sz;
            oe[10] = (1 - (xx + yy)) * sz;
            oe[11] = 0;
            oe[12] = te[0];
            oe[13] = te[1];
            oe[14] = te[2];
            oe[15] = 1;
        }
    
        public static createLookAt(eye:Vector3, target:Vector3, up:Vector3, out:Matrix4x4):void {
            var oE:Float32Array = out.elements;
            var xaxis:Vector3 = Matrix4x4._tempVector0;
            var yaxis:Vector3 = Matrix4x4._tempVector1;
            var zaxis:Vector3 = Matrix4x4._tempVector2;
            Vector3.subtract(eye, target, zaxis);
            Vector3.normalize(zaxis, zaxis);
            Vector3.cross(up, zaxis, xaxis);
            Vector3.normalize(xaxis, xaxis);
            Vector3.cross(zaxis, xaxis, yaxis);
            out.identity();
            oE[0] = xaxis.x;
            oE[4] = xaxis.y;
            oE[8] = xaxis.z;
            oE[1] = yaxis.x;
            oE[5] = yaxis.y;
            oE[9] = yaxis.z;
            oE[2] = zaxis.x;
            oE[6] = zaxis.y;
            oE[10] = zaxis.z;
            oE[12] = -Vector3.dot(xaxis, eye);
            oE[13] = -Vector3.dot(yaxis, eye);
            oE[14] = -Vector3.dot(zaxis, eye);
        }
    
        public static createPerspective(fov:number, aspect:number, near:number, far:number, out:Matrix4x4):void {
            var oe:Float32Array = out.elements;
            var f:number = 1.0 / Math.tan(fov / 2), nf = 1 / (near - far);
            oe[0] = f / aspect;
            oe[5] = f;
            oe[10] = (far + near) * nf;
            oe[11] = -1;
            oe[14] = (2 * far * near) * nf;
            oe[1] = oe[2] = oe[3] = oe[4] = oe[6] = oe[7] = oe[8] = oe[9] = oe[12] = oe[13] = oe[15] = 0;
        }
    
        public static createOrthoOffCenterRH(left:number, right:number, bottom:number, top:number, near:number, far:number, out:Matrix4x4):void {
            var oe:Float32Array = out.elements;
            var lr:number = 1 / (left - right);
            var bt:number = 1 / (bottom - top);
            var nf:number = 1 / (near - far);
            oe[1] = oe[2] = oe[3] = oe[4] = oe[6] = oe[7] = oe[8] = oe[9] = oe[11] = 0;
            oe[15] = 1;
            oe[0] = -2 * lr;
            oe[5] = -2 * bt;
            oe[10] = 2 * nf;
            oe[12] = (left + right) * lr;
            oe[13] = (top + bottom) * bt;
            oe[14] = (far + near) * nf;
        }
    
        public translation(v3:Vector3, out:Matrix4x4):void {
            var ve:Float32Array = v3.elements;
            var oe:Float32Array = out.elements;
            oe[0] = oe[5] = oe[10] = oe[15] = 1;
            oe[12] = ve[0];
            oe[13] = ve[1];
            oe[14] = ve[2];
        }
    }
}
